import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Semaphore;

/**
 * @author : lzp
 * @version 1.0
 * @date : 2022/9/8 15:35
 * @apiNote : abc线程轮流打印
 */
public class ThreadABCprint {
    public static void main(String[] args) {
        //ACB顺序,ABC顺序,CAB顺序都有可能发生
        //概率发生:如果A线程执行快会发生ACABC...ABCB的顺序,到最后ABCB的时候,B线程由于没有A线程的唤醒,如果wait不设置值的话会无限等待 仅在main函数里能复现
        Semaphore semaphoreA=new Semaphore(1);
        Semaphore semaphoreB=new Semaphore(1);
        Semaphore semaphoreC=new Semaphore(1);
        SwapThread swapThread = new SwapThread(semaphoreA,semaphoreB);
        SwapThread swapThread2 = new SwapThread(semaphoreB,semaphoreC);
        SwapThread swapThread3 = new SwapThread(semaphoreC,semaphoreA);
        swapThread.setName("A");
        swapThread.start();

        swapThread2.setName("B");
        swapThread2.start();

        swapThread3.setName("C");
        swapThread3.start();
    }
}
@Slf4j
class SwapThread extends  Thread{

    private final Semaphore semaphoreA;
    private final Semaphore semaphoreB;

    public SwapThread(Semaphore semaphoreA, Semaphore semaphoreB){
        this.semaphoreA = semaphoreA;
        this.semaphoreB = semaphoreB;
    }

    @Override
    public void run() {
        for (int i=0;i<10;i++){
            while (true)
                if (semaphoreA.tryAcquire()) {
                    //使用信号量防止死锁
                    if (semaphoreB.tryAcquire()) {
                        synchronized (semaphoreA){
                            log.info("获取锁1:{}", semaphoreA);
                            synchronized (semaphoreB){
                                log.info("获取锁2:{}  打印条件满足", semaphoreB);
                                System.out.println(Thread.currentThread().getName()+" : "+i);
                                //notifyAll并不会释放锁，代码块结束后释放锁
                                semaphoreB.notifyAll();
                            }
                            log.info("自动释放锁2:{}", semaphoreB);
                            try {
                                //避免程序不能正常结束
                                if (i>=9){
                                    log.info("线程打印任务结束,唤醒其他线程");
                                    semaphoreA.notifyAll();
                                    semaphoreB.release();
                                    semaphoreA.release();
                                }else{
                                    //wait方法将会释放锁标志，进入阻塞状态，等到唤醒
                                    semaphoreB.release();
                                    semaphoreA.release();
                                    log.info("wait释放锁1,等待下次唤醒:{}", semaphoreA);
                                    //防止乱序输出后线程得不到唤醒而无限等待
                                    semaphoreA.wait(10*1000);
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        break;
                    }else {
                        //如果获取不到第二个信号量,则释放已获取的信号量
                        semaphoreA.release();
                    }
                }
        }
    }
}
